/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.example.mediaplayerdemo;

import com.example.mediaplayerdemo.menu.Menu;
import com.example.mediaplayerdemo.menu.MeunItemType;
import com.example.mediaplayerdemo.widget.PlayerLoading;
import com.ryan.ohos.extension.util.WindowUtil;
import com.ryan.ohos.extension.widget.Toast;
import com.ryan.ohos.extension.widget.toolbar.Toolbar;
import net.protyposis.ohos.mediaplayer.*;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataAbilityRemoteException;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Component;
import ohos.agp.window.service.WindowManager;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.common.Source;
import ohos.utils.PacMap;
import ohos.utils.net.Uri;

import java.io.FileDescriptor;
import java.io.FileNotFoundException;

/**
 * VideoViewAbility
 */
public class VideoViewAbility extends Ability {

    private static final String TAG = VideoViewAbility.class.getSimpleName();

    private VideoView mVideoView;
    private SimplePlayerController mMediaController;
    private PlayerLoading mProgress;

    private Uri mVideoUri;
    private int mVideoPosition;
    private float mVideoPlaybackSpeed;
    private boolean mVideoPlaying;

    private EventHandler handler;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        super.setUIContent(ResourceTable.Layout_ability_video);

        WindowUtil.hideStatusBar(getWindow(), true);

        mVideoUri = intent.getUri();
        handler = new EventHandler(EventRunner.getMainEventRunner());

        initView();

        mVideoPosition = 0;
        mVideoPlaybackSpeed = 1;
        mVideoPlaying = false;
    }

    @Override
    protected void onActive() {
        super.onActive();

        if(!mVideoView.isPlaying()) {
            initPlayer();
        }
    }

    @Override
    protected void onStop() {
        if (null != mVideoView) {
            mVideoView.release();
            mVideoView = null;
        }
    }

    @Override
    public void onRestoreAbilityState(PacMap inState) {
        super.onRestoreAbilityState(inState);

        mVideoUri = Uri.parse(inState.getString("uri"));
        mVideoPosition = inState.getIntValue("position");
        mVideoPlaybackSpeed = inState.getFloatValue("playbackSpeed");
        mVideoPlaying = inState.getBooleanValue("playing");
    }

    @Override
    public void onSaveAbilityState(PacMap outState) {
        super.onSaveAbilityState(outState);

        if (mVideoView != null) {
            mVideoPosition = mVideoView.getCurrentPosition();
            mVideoPlaybackSpeed = mVideoView.getPlaybackSpeed();
            mVideoPlaying = mVideoView.isPlaying();
            // the uri is stored in the base activity
            outState.putString("uri", mVideoUri.toString());
            outState.putIntValue("position", mVideoPosition);
            outState.putFloatValue("playbackSpeed", mVideoView.getPlaybackSpeed());
            outState.putBooleanValue("playing", mVideoPlaying);
        }
    }

    private void initView() {
        Toolbar toolbar = (Toolbar) findComponentById(ResourceTable.Id_nav);
        toolbar.setTitle("VideoView Demo");
        toolbar.setSubtitle(mVideoUri.toString());
        toolbar.setContentInsetStartWithNavigation(0);

        Menu menu = new Menu(getContext(), findComponentById(ResourceTable.Id_menu));
        menu.add(MeunItemType.NO_SUB, ResourceTable.String_action_reload_source)
                .setOnMenuItemClickListener(item -> {
                    initPlayer();
                    mVideoView.setPlaybackSpeed(1.0f);
                    return true;
                });
        menu.add(MeunItemType.NO_SUB, ResourceTable.String_action_slowspeed)
                .setOnMenuItemClickListener(item -> {
                    mVideoView.setPlaybackSpeed(0.2f);
                    return true;
                });
        menu.add(MeunItemType.NO_SUB, ResourceTable.String_action_halfspeed)
                .setOnMenuItemClickListener(item -> {
                    mVideoView.setPlaybackSpeed(0.5f);
                    return true;
                });
        menu.add(MeunItemType.NO_SUB, ResourceTable.String_action_normalspeed)
                .setOnMenuItemClickListener(item -> {
                    mVideoView.setPlaybackSpeed(1.0f);
                    return true;
                });
        menu.add(MeunItemType.NO_SUB, ResourceTable.String_action_doublespeed)
                .setOnMenuItemClickListener(item -> {
                    mVideoView.setPlaybackSpeed(2.0f);
                    return true;
                });
        menu.add(MeunItemType.NO_SUB, ResourceTable.String_action_quadspeed)
                .setOnMenuItemClickListener(item -> {
                    mVideoView.setPlaybackSpeed(4.0f);
                    return true;
                });
        menu.add(MeunItemType.NO_SUB, ResourceTable.String_action_seekcurrentposition)
                .setOnMenuItemClickListener(item -> {
                    mVideoView.pause();
                    mVideoView.seekTo(mVideoView.getCurrentPosition());
                    return true;
                });
        menu.add(MeunItemType.NO_SUB, ResourceTable.String_action_seekcurrentpositionplus1ms)
                .setOnMenuItemClickListener(item -> {
                    mVideoView.pause();
                    mVideoView.seekTo(mVideoView.getCurrentPosition() + 1);
                    return true;
                });
        menu.add(MeunItemType.NO_SUB, ResourceTable.String_action_seektoend)
                .setOnMenuItemClickListener(item -> {
                    mVideoView.seekTo(mVideoView.getDuration());
                    mVideoView.pause();
                    return true;
                });
        menu.add(MeunItemType.NO_SUB, ResourceTable.String_action_getcurrentposition)
                .setOnMenuItemClickListener(item -> {
                    Toast.show(getContext(), "current position: " + mVideoView.getCurrentPosition());
                    return true;
                });


        mVideoView = (VideoView) findComponentById(ResourceTable.Id_play_surface);
        mMediaController = (SimplePlayerController) findComponentById(ResourceTable.Id_controller);
        mMediaController.setMediaPlayer(mVideoView);
        Runnable hide = () -> mMediaController.setVisibility(Component.HIDE);
        findComponentById(ResourceTable.Id_wrapper).setClickedListener(l -> {
            if (mMediaController.getVisibility() == Component.VISIBLE) {
                mMediaController.setVisibility(Component.HIDE);
                handler.removeTask(hide);
            } else {
                mMediaController.setVisibility(Component.VISIBLE);
                handler.postTask(hide, 3000);
            }
        });

        mProgress = (PlayerLoading) findComponentById(ResourceTable.Id_loading_view);
        mProgress.setPlayer(mVideoView);

        WindowManager.getInstance().getTopWindow().get().setTransparent(true);
    }

    private void initPlayer() {
        mVideoView.setOnPreparedListener(vp -> {
            mProgress.setVisibility(Component.HIDE);
            mMediaController.setEnabled(true);

//            vp.addCue(1000, "test cue @ 1000");
//            vp.addCue(2000, "test cue @ 2000");
//            vp.addCue(3000, "test cue @ 3000");
//            vp.addCue(10000, "test cue @ 10000");
//            vp.setOnCueListener(new MediaPlayer.OnCueListener() {
//                @Override
//                public void onCue(MediaPlayer mp, Cue cue) {
//                    LogUtil.loge(TAG, "onCue: " + cue.toString() + " (" + mp.getCurrentPosition() + ")");
//                }
//            });
        });
        mVideoView.setOnErrorListener((mp, what, extra) -> {
            Toast.show(getContext(), "Cannot play the video, see logcat for the detailed exception");
            mProgress.setVisibility(Component.HIDE);
            mMediaController.setEnabled(false);
            return true;
        });
        mVideoView.setOnInfoListener((mp, what, extra) -> {
            String whatName = "";
            switch (what) {
                case MediaPlayer.MEDIA_INFO_BUFFERING_END:
                    whatName = "MEDIA_INFO_BUFFERING_END";
                    break;
                case MediaPlayer.MEDIA_INFO_BUFFERING_START:
                    whatName = "MEDIA_INFO_BUFFERING_START";
                    break;
                case MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START:
                    whatName = "MEDIA_INFO_VIDEO_RENDERING_START";
                    break;
                case MediaPlayer.MEDIA_INFO_VIDEO_TRACK_LAGGING:
                    whatName = "MEDIA_INFO_VIDEO_TRACK_LAGGING";
                    break;
            }
            LogUtil.loge(TAG, "onInfo " + whatName);
            return false;
        });
        mVideoView.setOnSeekListener(mp -> {
            LogUtil.loge(TAG, "onSeek");
            mProgress.setVisibility(Component.VISIBLE);
        });
        mVideoView.setOnSeekCompleteListener(mp -> {
            LogUtil.loge(TAG, "onSeekComplete");
            mProgress.setVisibility(Component.HIDE);
        });
        mVideoView.setOnBufferingUpdateListener((mp, percent) -> LogUtil.loge(TAG, "onBufferingUpdate " + percent + "%"));

        playMediaFile();
    }

    private void playMediaFile() {
        try {
            Source source;
            if (mVideoUri.getScheme().equals("dataability")) {
                DataAbilityHelper helper = DataAbilityHelper.creator(getContext());
                FileDescriptor fd = helper.openFile(mVideoUri, "r");
                source = new Source(fd);
            } else {
                source = new Source(mVideoUri.toString());
            }

            mVideoView.setVideoSource(source);
            mVideoView.seekTo(mVideoPosition);
            mVideoView.setPlaybackSpeed(mVideoPlaybackSpeed);
            if (mVideoPlaying) {
                mVideoView.start();
            }
        } catch (DataAbilityRemoteException | FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onBackPressed() {
        if (mProgress.isShowing()) {
            mProgress.hide();
        } else {
            super.onBackPressed();
        }
    }

    @Override
    protected void onBackground() {
        super.onBackground();
        mMediaController.reset();
        mMediaController.setVisibility(Component.HIDE);
    }
}
